/*
 * Copyright (c) 2009 DeledImporter
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'Pyro Games' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.pyrogames.ardor3d.extension;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import net.pyrogames.deled.geometry.DXSNode;
import net.pyrogames.deled.importer.DXSExtension;
import net.pyrogames.deled.light.DXSDirectionalLight;
import net.pyrogames.deled.light.DXSLight;
import net.pyrogames.deled.light.DXSPointLight;
import net.pyrogames.deled.light.DXSSpotLight;
import net.pyrogames.deled.material.DXSColorRGBA;
import net.pyrogames.deled.math.DXSVector3f;

/**
 * A <code>DXSImporter</code> extension that processes a light element
 * and creates a <code>{@link DXSLightNode}</code> for it. This allows us
 * to give special status to this node (and its light) for when we convert it
 * to an engine later on in a <code>Format</code> object.
 * <p>
 * Note the <code>DXSLightNode</code> is a custom element that allows us
 * to change the internal hierarchy without changing anything else.
 * 
 * @author Nicholas Woodfield
 *
 */

public class LightNodeExtension implements DXSExtension {

	@Override
	public boolean executeExtension(DXSNode node, Element dxsElem) {
		//Ensure we're dealing with a light
		if(dxsElem.getNodeName().equals("light")){
			//Process the light
			DXSLight light = processLight(dxsElem);
			//Create a new light node with the specified light
			DXSLightNode lightNode = new DXSLightNode(light.getName(),light);
			//Attach the light node to our specified root
			node.attachChild(lightNode);
			return true;
		}
		//We didn't do anything, return false
		return false;
	}
	
	private DXSLight processLight(Element dxsElem) {
		//Get the document root so we can get the ambient light setting (bit of a hack here)
		Element docRoot = dxsElem.getOwnerDocument().getDocumentElement();
		Element elem = (Element) docRoot.getElementsByTagName("ambient").item(0);
		
		//Set ambient
		DXSColorRGBA ambient = new DXSColorRGBA();
		ambient.r = Float.parseFloat(elem.getAttribute("r")) / 255;
		ambient.g = Float.parseFloat(elem.getAttribute("g")) / 255;
		ambient.b = Float.parseFloat(elem.getAttribute("b")) / 255;
		
		//Get if its enabled or not
		boolean active = Boolean.valueOf(dxsElem.getAttribute("active"));
		
		//Get if it casts shadows or not
		boolean castShadows = Boolean.valueOf(dxsElem.getAttribute("castShadows"));
		
		//Get the name of the light
		String name = dxsElem.getAttribute("name");
		
		//Get the type of light
		String type = dxsElem.getAttribute("type");
		
		//Get the diffuse color
		NodeList diffList = dxsElem.getElementsByTagName("diffuse");
		Element diff = (Element) diffList.item(0);
		DXSColorRGBA diffuse = new DXSColorRGBA();
		diffuse.r = Float.parseFloat(diff.getAttribute("r")) / 255;
		diffuse.g = Float.parseFloat(diff.getAttribute("g")) / 255;
		diffuse.b = Float.parseFloat(diff.getAttribute("b")) / 255;
		
		//Get the specular color
		NodeList specs = dxsElem.getElementsByTagName("specular");
		Element spec = (Element) specs.item(0);
		DXSColorRGBA specular = new DXSColorRGBA();
		specular.r = Float.parseFloat(spec.getAttribute("r")) / 255;
		specular.g = Float.parseFloat(spec.getAttribute("g")) / 255;
		specular.b = Float.parseFloat(spec.getAttribute("b")) / 255;
		
		//Determine the correct type of light
		if(type.equals("point")){
			
			//Get attenuation variables
			NodeList atts = dxsElem.getElementsByTagName("attenuation");
			Element attenuation = (Element) atts.item(0);
			float constant = Float.parseFloat(attenuation.getAttribute("constant"));
			float linear = Float.parseFloat(attenuation.getAttribute("linear"));
			float quadratic = Float.parseFloat(attenuation.getAttribute("quadratic"));
			
			//Get the position of the light
			DXSVector3f pos = new DXSVector3f();
			NodeList positions = dxsElem.getElementsByTagName("position");
			Element position = (Element) positions.item(0);
			pos.x = Float.parseFloat(position.getAttribute("x"));
			pos.y = Float.parseFloat(position.getAttribute("y"));
			pos.z = Float.parseFloat(position.getAttribute("z"));
			
			//create the point light
			DXSPointLight pLight = new DXSPointLight(name, pos);
			
			//Set attributes
			pLight.setAmbient(ambient);
			pLight.setDiffuse(diffuse);
			pLight.setSpecular(specular);
			pLight.setAttenuate(true);
			pLight.setEnabled(active);
			pLight.setConstant(constant);
			pLight.setLinear(linear);
			pLight.setQuadratic(quadratic);
			pLight.setShadowCaster(castShadows);
			
			//Add the light to the scene
			return pLight;
			
		} else if(type.equals("directional")){
			
			//Get the direction of the light
			DXSVector3f dir = new DXSVector3f();
			NodeList directions = dxsElem.getElementsByTagName("direction");
			Element direction = (Element) directions.item(0);
			dir.x = Float.parseFloat(direction.getAttribute("x"));
			dir.y = Float.parseFloat(direction.getAttribute("y"));
			dir.z = Float.parseFloat(direction.getAttribute("z"));
			
			//create the spot light
			DXSDirectionalLight dLight = new DXSDirectionalLight(name,dir);
			
			//Set attributes
			dLight.setAmbient(ambient);
			dLight.setDiffuse(diffuse);
			dLight.setSpecular(specular);
			dLight.setEnabled(active);
			dLight.setShadowCaster(castShadows);
			
			return dLight;
			
		} else if(type.equals("spot")){
			
			//Get attenuation variables
			NodeList atts = dxsElem.getElementsByTagName("attenuation");
			Element attenuation = (Element) atts.item(0);
			float constant = Float.parseFloat(attenuation.getAttribute("constant"));
			float linear = Float.parseFloat(attenuation.getAttribute("linear"));
			float quadratic = Float.parseFloat(attenuation.getAttribute("quadratic"));
			
			//Get the position of the light
			DXSVector3f pos = new DXSVector3f();
			NodeList positions = dxsElem.getElementsByTagName("position");
			Element position = (Element) positions.item(0);
			pos.x = Float.parseFloat(position.getAttribute("x"));
			pos.y = Float.parseFloat(position.getAttribute("y"));
			pos.z = Float.parseFloat(position.getAttribute("z"));
			
			//Get the direction of the light
			DXSVector3f dir = new DXSVector3f();
			NodeList directions = dxsElem.getElementsByTagName("direction");
			Element direction = (Element) directions.item(0);
			dir.x = Float.parseFloat(direction.getAttribute("x"));
			dir.y = Float.parseFloat(direction.getAttribute("y"));
			dir.z = Float.parseFloat(direction.getAttribute("z"));
			
			//Get cone attributes
			NodeList cones = dxsElem.getElementsByTagName("cone");
			Element cone = (Element) cones.item(0);
			float innerAngle = Float.parseFloat(cone.getAttribute("inner"));
			float outerAngle = Float.parseFloat(cone.getAttribute("outer"));
			float falloff = Float.parseFloat(cone.getAttribute("falloff"));
			
			//create the spot light
			DXSSpotLight sLight = new DXSSpotLight(name, pos, dir, innerAngle, outerAngle, falloff);
			
			//Set attributes
			sLight.setAmbient(ambient);
			sLight.setDiffuse(diffuse);
			sLight.setSpecular(specular);
			sLight.setAttenuate(true);
			sLight.setEnabled(active);
			sLight.setConstant(constant);
			sLight.setLinear(linear);
			sLight.setQuadratic(quadratic);
			sLight.setShadowCaster(castShadows);
			
			return sLight;
		}
		return null;
	}

}
